﻿using System.Runtime.CompilerServices;
using Unity.Mathematics;

namespace Game.FlowField.Burst
{
    public static class MapDataUtil
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetRightIndex2D(int2 gridIndex2D, int mapWidth, out int2 result)
        {
            result = gridIndex2D;
            result.x++;
            return 0 <= result.x && result.x < mapWidth;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetLeftIndex2D(int2 gridIndex2D, int mapWidth, out int2 result)
        {
            result = gridIndex2D;
            result.x--;
            return 0 <= result.x && result.x < mapWidth;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetTopIndex2D(int2 gridIndex2D, int mapHeight, out int2 result)
        {
            result = gridIndex2D;
            result.y++;
            return 0 <= result.y && result.y < mapHeight;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetBottomIndex2D(int2 gridIndex2D, int mapHeight, out int2 result)
        {
            result = gridIndex2D;
            result.y--;
            return 0 <= result.y && result.y < mapHeight;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetTopRightIndex2D(int2 gridIndex2D, int2 mapSize, out int2 result)
        {
            result = gridIndex2D;
            result.xy += 1;
            return 0 <= result.x && result.x < mapSize.x &&
                   0 <= result.y && result.y < mapSize.y;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetTopLeftIndex2D(int2 gridIndex2D, int2 mapSize, out int2 result)
        {
            result = gridIndex2D;
            result.xy += new int2(-1, 1);
            return 0 <= result.x && result.x < mapSize.x &&
                   0 <= result.y && result.y < mapSize.y;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetBottomLeftIndex2D(int2 gridIndex2D, int2 mapSize, out int2 result)
        {
            result = gridIndex2D;
            result.xy += -1;
            return 0 <= result.x && result.x < mapSize.x &&
                   0 <= result.y && result.y < mapSize.y;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool GetBottomRightIndex2D(int2 gridIndex2D, int2 mapSize, out int2 result)
        {
            result = gridIndex2D;
            result.xy += new int2(1, -1);
            return 0 <= result.x && result.x < mapSize.x &&
                   0 <= result.y && result.y < mapSize.y;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool IsInsideMap(int2 gridIndex2D, int2 mapSize)
        {
            if (gridIndex2D.x < 0)
                return false;

            if (gridIndex2D.y < 0)
                return false;

            if (gridIndex2D.x >= mapSize.x)
                return false;

            if (gridIndex2D.y >= mapSize.y)
                return false;

            return true;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool TryGetIndexByIndex2DWithBoundaryChecking(int2 gridIndex2D, int2 mapSize, out int gridIndex)
        {
            gridIndex = default;

            if (gridIndex2D.x < 0)
                return false;

            if (gridIndex2D.y < 0)
                return false;

            if (gridIndex2D.x >= mapSize.x)
                return false;

            if (gridIndex2D.y >= mapSize.y)
                return false;

            gridIndex = gridIndex2D.x * mapSize.y + gridIndex2D.y;

            return true;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int ConvertIndex2D2Index(int2 gridIndex2D, int2 mapSize)
        {
            return gridIndex2D.x * mapSize.y + gridIndex2D.y;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int2 ConvertIndex2Index2D(int gridIndex, int2 mapSize)
        {
            int2 gridIndex2D;
            gridIndex2D.x = gridIndex / mapSize.y;
            gridIndex2D.y = gridIndex % mapSize.y;
            return gridIndex2D;
        }
    }
}